#pragma once

#include<string>
#include<vector>
#include<fstream>
#include<boost/algorithm/string.hpp>
#include<mutex>
#include "cppjieba/Jieba.hpp"
#include"util.hpp"
#define path "./data/raw_html/raw.txt"

//#define  Inverted_zip std::vector<InvertedDate>


namespace ns_index{

//正排数据
struct DocInfo{
    std::string title;
    std::string content;
    std::string url;
    int InfoId;
};

//倒排数据
struct  InvertedDate{
    std::string word;
    int weight;
    int InfoId;
};

#define  Inverted_zip std::vector<InvertedDate>

class Index{
//倒排拉链
//#define  Inverted_zip std::vector<InvertedDate>

private:
    Index(){};
    Index(const Index& x)=delete;
    Index operator=(const Index& x)=delete;
    
    ~Index(){};
public:
    static Index* Get_Index()
    {
      if(index_obj==nullptr)
      {
        //线程安全
        std::mutex m;
        m.lock();
        if(index_obj==nullptr)
        {
          index_obj=new Index();
          std::cout<<"创建Index单例成功"<<std::endl;
        }
        m.unlock();
      }

      return index_obj;
    }
private:
//建立正排索引
    bool bulid_forward(std::ifstream& In)
    {
        int count=0;
        #define seg "\x03"
        std::string s;
        while(getline(In,s))
        {
            DocInfo d;
            std::vector<std::string> vc;
            boost::split(vc,s,boost::is_any_of(seg),boost::token_compress_on);
            if(vc.size()!=3)
            {
                continue;
                //return false;
            }

            d.title=vc[0];
            d.content=vc[1];
            d.url=vc[2];
            d.InfoId=infos.size();
            infos.push_back(d);
            count++;
            //debug
            // if((count%50)==0)
            // {
            //     std::cout<<"bulid_forward:"<<count<<" success"<<std::endl;
            // }
        }
        return true;
    }

    //建立倒排索引
    bool bulid_Inverted()
    {
        struct Count{
            int title_count;
            int content_count;
            Count()
            :title_count(0)
            ,content_count(0){}
        };

        #define title_score 10
        #define content_score 1

        //对文档进行倒排索引
         int count=0;
        for(auto& info: infos)
        {
            //对标题进行分词
            std::vector<std::string> titlewords;
            Util::StringUtil::Cutstring(info.title,&titlewords);

            //对内容进行分词
            std::vector<std::string> contentwords;
            Util::StringUtil::Cutstring(info.content,&titlewords);

            //记录词条在标题以及正文中出现的次数
            std::map<std::string,Count> mp_count;

            for(auto&e:titlewords)
            {
                //我们统一处理成小写，在搜索引擎中小写也能搜到大写
                boost::to_lower(e);
                mp_count[e].title_count++;
            }

            for(auto&e:contentwords)
            {
                boost::to_lower(e);
                mp_count[e].content_count++;
            }

            //创建倒排数据
            auto it=mp_count.begin();
            while(it!=mp_count.end())
            {
                InvertedDate inver;
                inver.word=it->first;
                inver.InfoId=info.InfoId;
                inver.weight=(it->second.title_count)*title_score+ (it->second.content_count)*content_score;
                Inverted_zip_mp[it->first].push_back(std::move(inver));//move减少拷贝
                it++;
            }

            //debug
            count++;
            if((count%50)==0)
            {
                std::cout<<"bulid_Inverted:"<<count<<" success"<<std::endl;

            }
        }
        return true;
    }

public:
    //建立索引
    bool bulid_index(std::string file_path=path)
    {
        std::ifstream In(file_path,std::ifstream::in);//读取文件
        if(!bulid_forward(In))
        {
            std::cerr<<"bulid_forward err"<<std::endl;
            return false;
        }
        std::cout<<"bulid_forward success"<<std::endl;
        
        //debug
        // for(auto& info:infos)
        // {   
        //     std::cout<<info.title<<std::endl;
        //     std::cout<<info.content<<std::endl;
        //     std::cout<<info.url<<std::endl;
        //     std::cout<<info.InfoId<<std::endl;
        // }

        if(!bulid_Inverted())
        {
            std::cerr<<"bulid_Inverted err"<<std::endl;
            return false;
        }
        std::cout<<"bulid_Inverted success"<<std::endl;

        return true;
    }

    //指针返回减少拷贝
    DocInfo* Get_DocInfo(int infoid)
    {
        if(infoid>=infos.size())
        {
            return nullptr;
        }
        return &infos[infoid];
    }

    Inverted_zip* Get_Inverted_zip(std::string query)
    {
        if(Inverted_zip_mp[query].size()==0)
        {
            return nullptr;
        }
        return &Inverted_zip_mp[query];
    }
    

private:
    std::vector<DocInfo> infos;//正排索引
    std::map<std::string,Inverted_zip> Inverted_zip_mp;//倒排拉链
    static Index* index_obj;//单例
};
    Index* Index::index_obj=nullptr;
};

